#include "StdAfx.h"
#include "GravitronFactory.h"
#include <cmath>

#define PI 3.1415926
GravitronFactory::GravitronFactory(void)
{
	m_wheelRotateDegrees = 0;
	m_timeElapsed = 0;
	m_waitTime = 0;

	m_Gravitron = new CSgComposite();
	m_Disc = new CSgComposite();

	m_RotationPoint = new CSgRotateAroundPoint(m_wheelRotateDegrees,
		CGrVector(1.5, 4.5, 1.5),
		CGrVector(0, 1, 0));
}

GravitronFactory::~GravitronFactory(void)
{
}

CSgObject* GravitronFactory::Create(void)
{
	CSgPtr<CSgSeparator> main_sep = new CSgSeparator();
	CreateBase();
	CreateTop();
	CreateBottom();
	CreateRim();

	m_RotationPoint->SetChild( m_Disc );
	m_Gravitron->AddChild(m_RotationPoint);

	return m_Gravitron;
}

void GravitronFactory::AdvanceTime(const DWORD & timeDiff, const DWORD & currentTime)
{
	int diff = timeDiff/1000; // seconds

	if( m_timeElapsed % 100 == 0)
	{
		if(m_waitTime < 30)
			m_waitTime++;
		else
		{
			m_timeElapsed++;
			m_waitTime = 0;
		}

		m_wheelRotateDegrees = 0;
		if( m_RotationPoint != NULL)
			m_RotationPoint->SetDegrees( m_wheelRotateDegrees);
		return;
	}
	else
	{
		const int incrementDegrees = (int)((double)timeDiff / 10.);
		m_wheelRotateDegrees = (m_wheelRotateDegrees + incrementDegrees) % 360;
	}

	if( m_RotationPoint != NULL)
		m_RotationPoint->SetDegrees( m_wheelRotateDegrees);

	m_timeElapsed++;
}

void GravitronFactory::CreateBase(void)
{

	double a[] = {0., 0., 0., 1.};
    double b[] = {3., 0., 0., 1.};
    double c[] = {0., 0., 3., 1.};
    double d[] = {3., 0., 3., 1.};
    double e[] = {1.5, 3, 1.5, 1.};

	double n[5][4] = {{0, 1, 0, 0}, // bottom
	{0, .4472, .894, 0}, //front
	{.894, -.447, 0, 0},  // left
	{0, -.4472, 0.894, 0}, //  back
	{.894, .447, 0, 0}}; //right

	CSgPtr<CSgMesh> base = new CSgMesh();
	base->SetTexture( *baseTex );

	for(int i=0; i<5; i++)
		base->AddNormal( n[i] );

	base->AddTexCoord( CGrVector(.5, 0, 0));
	base->AddTexCoord( CGrVector( 0, 1, 0));
	base->AddTexCoord( CGrVector( 1, 1, 0));

	base->AddVertex( CGrVector(a) );
	base->AddVertex( CGrVector(b) );
	base->AddVertex( CGrVector(c) );
	base->AddVertex( CGrVector(d) );
	base->AddVertex( CGrVector(e) );

	//bottom
	base->AddTriangleVertex(0, 0, -1);
	base->AddTriangleVertex(3, 0, -1);
	base->AddTriangleVertex(2, 0, -1);
	
	base->AddTriangleVertex(0, 0, -1);
	base->AddTriangleVertex(1, 0, -1);
	base->AddTriangleVertex(3, 0, -1);

	//front
	base->AddTriangleVertex(4, 1, 0);
	base->AddTriangleVertex(2, 1, 1);
	base->AddTriangleVertex(3, 1, 2);

	//right
	base->AddTriangleVertex(4, 4, 0);
	base->AddTriangleVertex(3, 4, 1);
	base->AddTriangleVertex(1, 4, 2);

	//back
	base->AddTriangleVertex(4, 3, 0);
	base->AddTriangleVertex(1, 3, 1);
	base->AddTriangleVertex(0, 3, 2);

	//left
	base->AddTriangleVertex(4, 2, 0);
	base->AddTriangleVertex(0, 2, 1);
	base->AddTriangleVertex(2, 2, 2);

	m_Gravitron->AddChild( base );
}

void GravitronFactory::CreateTop()
{
	CSgPtr<CSgMesh> top = new CSgMesh();
	top->SetTexture( *topTex );

	CGrVector center(1.5 , 7, 1.5);
	top->AddVertex( center );
	
	CGrVector prev_vertex = center;

	top->AddTexCoord(CGrVector(0, 1, 0));
	top->AddTexCoord( CGrVector(.5, 0, 0));
	top->AddTexCoord( CGrVector(1, 1,0));

	for(int j=0; j<100; j++)
	{
		double angle = (2*PI)/100;
		double radius = 5;
		CGrVector vertex(center.X() + radius * sin(angle * j), 5., center.Z() + radius * cos(angle * j));

		top->AddVertex( vertex );

		if( j == 0)
		{
			prev_vertex = vertex;
			continue;
		}
		
		CGrVector normal = Cross3( 
				CGrVector( prev_vertex - center ), 
				CGrVector( vertex - center));
		normal.Normalize3();

		top->AddNormal( normal );

		top->AddTriangleVertex( 0, j-1, 1 );
		top->AddTriangleVertex( j, j-1, 2 );
		top->AddTriangleVertex( j + 1, j-1, 0 );

		prev_vertex = vertex;
	}

	top->AddTriangleVertex( 0, 100, 1 );
	top->AddTriangleVertex( 100, 100, 2 );
	top->AddTriangleVertex( 1, 100, 0 );

	top->ComputeSmoothNormals();

	m_Disc->AddChild( top );

}

void GravitronFactory::CreateBottom(void)
{
	CSgPtr<CSgMesh> bottom = new CSgMesh();
	bottom->SetTexture( *botTex);

	CGrVector center(1.5 , 2, 1.5);
	CGrVector prev_vertex = center;

	bottom->AddVertex( center );

	bottom->AddTexCoord(CGrVector(0, 1, 0));
	bottom->AddTexCoord( CGrVector(.5, 0, 0));
	bottom->AddTexCoord( CGrVector(1, 1,0));

	for(int j=0; j<100; j++)
	{
		double angle = (2*PI)/100;
		double radius = 5;
		CGrVector vertex(center.X() + radius * sin(angle * j), 4., center.Z() + radius * cos(angle * j));

		bottom->AddVertex( vertex );

		if( j == 0)
		{
			prev_vertex = vertex;
			continue;
		}
		
		CGrVector normal = Cross3( 
				CGrVector( prev_vertex - center ), 
				CGrVector( vertex - center));
		normal.Normalize3();

		bottom->AddNormal( normal );

		bottom->AddTriangleVertex( 0, j-1, 1 );
		bottom->AddTriangleVertex( j + 1, j-1, 2 );
		bottom->AddTriangleVertex( j, j-1, 0 );
	}


	bottom->AddTriangleVertex( 0,100, 1);
	bottom->AddTriangleVertex( 1, 100, 2 );
	bottom->AddTriangleVertex( 100, 100, 0 );


	m_Disc->AddChild( bottom );
}

void GravitronFactory::CreateRim(void)
{	
	CSgPtr<CSgMesh> rim = new CSgMesh();

	double top_center[] = {1.5 , 7, 1.5};
	double bottom_center[] = {1.5 , 2, 1.5};

	CGrVector prev_top = top_center;
	CGrVector prev_bottom = bottom_center;

	rim->SetTexture(*rimTex);

	rim->AddTexCoord( CGrVector( 0, 0, 0));
	rim->AddTexCoord( CGrVector(0, 25, 0));
	rim->AddTexCoord( CGrVector(25, 25,0));
	rim->AddTexCoord( CGrVector(25, 0, 0));

	for(int j=0; j<100; j++)
	{
		double angle = (2*PI)/100;
		double radius = 5;
		CGrVector top_vertex(top_center[0] + radius * sin(angle * j), 5, top_center[2] + radius * cos(angle * j));
		CGrVector bottom_vertex(bottom_center[0] + radius * sin(angle * j), 4, bottom_center[2] + radius * cos(angle * j));

		rim->AddVertex( top_vertex );
		rim->AddVertex( bottom_vertex );

		if( j == 0)
		{
			prev_top = top_vertex;
			prev_bottom = bottom_vertex;
			continue;
		}

		CGrVector normal1 = Cross3( 
			CGrVector( prev_top - prev_bottom),
			CGrVector( bottom_vertex - prev_bottom));
		rim->AddNormal( normal1 );

		//First triangle of square
		rim->AddTriangleVertex(j*2-2, j*2-2, 0);
		rim->AddTriangleVertex(j*2-1, j*2-2, 1);
		rim->AddTriangleVertex(j*2+1, j*2-2, 2);

		CGrVector normal2 = Cross3( 
			CGrVector( prev_top - top_vertex),
			CGrVector( bottom_vertex - top_vertex));
		rim->AddNormal( normal2 );
		//Second triangle of square
		rim->AddTriangleVertex(j*2-2, j*2-1, 0);
		rim->AddTriangleVertex(j*2+1, j*2-1, 2);
		rim->AddTriangleVertex(j*2, j*2-1 , 3);
	}

	//Final Square
	rim->AddTriangleVertex(198, 0, 0);
	rim->AddTriangleVertex(199, 0, 1);
	rim->AddTriangleVertex(1, 0, 2);
	rim->AddTriangleVertex(198, 0, 0);
	rim->AddTriangleVertex(1, 0, 2);
	rim->AddTriangleVertex(0, 0 ,3);

	rim->ComputeSmoothNormals();
	
	m_Disc->AddChild( rim );
}
